/****************************************************************************/
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
// Copyright (C) 2007-2024 German Aerospace Center (DLR) and others.
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0/
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License 2.0 are satisfied: GNU General Public License, version 2
// or later which is available at
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
/****************************************************************************/
/// @file    SAXWeightsHandler.h
/// @author  Daniel Krajzewicz
/// @author  Jakob Erdmann
/// @author  Michael Behrisch
/// @date    Fri, 30 Mar 2007
///
// An XML-handler for network weights
/****************************************************************************/
#pragma once
#include <config.h>

#include <string>
#include <utils/xml/SUMOSAXHandler.h>
#include <utils/common/SUMOTime.h>


// ===========================================================================
// class definitions
// ===========================================================================
/**
 * @class SAXWeightsHandler
 * @brief An XML-handler for network weights
 *
 * As network weights are used both in the simulation and the routers, a base
 *  class for loading them was built. Instances of this class should be supplied
 *  with at least one definition about what shall be retrieved
 *  (ToRetrieveDefinition, defined as inner class) which also contains the information
 *  about the retriever (EdgeFloatTimeLineRetriever, defined as inner class).
 *
 * The ToRetrieveDefinition names the attribute which the SAXWeightsHandler shall
 *  parse and reporte. Within the parsed xml-file these attributes may be embedded
 *  in "lane" or "edge" elements, one for each edge or for each lane (see below).
 *  These elements should be embedded in interval-tags which specify the time the
 *  weight is valid at.
 *  The boolean "edgeBased" tells SAXWeightsHandler whether the weights are supplied
 *  on edge- or on lane-basis (whether it shall parse the "edge" or the "lane" elements).
 *
 * Examples for files the SAXWeightsHandler can handle are the edgedump and the lanedump
 *  generated by the simulation.
 *
 * The EdgeFloatTimeLineRetriever to which read values will be reported should have the
 *  method "addEdgeWeight" implemented. It wil be supplied with the current edge name,
 *  the interval the weight is valid for and the value.
 */
class SAXWeightsHandler : public SUMOSAXHandler {
public:
    /**
     * @class EdgeFloatTimeLineRetriever
     * @brief Interface for a class which obtains read weights for named edges
     */
    class EdgeFloatTimeLineRetriever {

    public:
        /// @brief Constructor
        EdgeFloatTimeLineRetriever() { }

        /// @brief Destructor
        virtual ~EdgeFloatTimeLineRetriever() { }

        /** @brief Adds a weight for a given edge and time period
         *
         * @param[in] id The id of the object to add a weight for
         * @param[in] val The weight
         * @param[in] beg The begin of the interval the weight is valid for
         * @param[in] end The end of the interval the weight is valid for
         */
        virtual void addEdgeWeight(const std::string& id, double val, double beg, double end) const {
            UNUSED_PARAMETER(id);
            UNUSED_PARAMETER(val);
            UNUSED_PARAMETER(beg);
            UNUSED_PARAMETER(end);
        }

        virtual void addEdgeRelWeight(const std::string& from, const std::string& to,
                                      double val, double beg, double end) const {
            UNUSED_PARAMETER(from);
            UNUSED_PARAMETER(to);
            UNUSED_PARAMETER(val);
            UNUSED_PARAMETER(beg);
            UNUSED_PARAMETER(end);
        }

        /// @note: note sure why the other functions are const
        virtual void addTazRelWeight(const std::string intervalID, const std::string& from, const std::string& to,
                                     double val, double beg, double end) {
            UNUSED_PARAMETER(intervalID);
            UNUSED_PARAMETER(from);
            UNUSED_PARAMETER(to);
            UNUSED_PARAMETER(val);
            UNUSED_PARAMETER(beg);
            UNUSED_PARAMETER(end);
        }

    private:
        /// @brief we made the assignment operator invalid
        EdgeFloatTimeLineRetriever& operator=(const EdgeFloatTimeLineRetriever&) = delete;
    };

    /**
     * @class ToRetrieveDefinition
     * @brief Complete definition about what shall be retrieved and where to store it
     */
    class ToRetrieveDefinition {
    public:
        /// @brief Constructor
        ToRetrieveDefinition(const std::string& attributeName, bool edgeBased,
                             EdgeFloatTimeLineRetriever& destination);

        /// Destructor
        ~ToRetrieveDefinition();

    public:
        /// @brief The attribute name that shall be parsed
        std::string myAttributeName;

        /// @brief Information whether edge values shall be used (lane value if false)
        bool myAmEdgeBased;

        /// @brief The class that shall be called when new data is avaiable
        EdgeFloatTimeLineRetriever& myDestination;

        /// @brief Aggregated value over the lanes read within the current edge
        double myAggValue;

        /// @brief The number of lanes read for the current edge
        int myNoLanes;

        /// @brief Information whether the attribute has been found for the current edge
        bool myHadAttribute;

        /// @brief Information whether the attribute was found to contain non-numerical data (for any edge)
        bool myHadNonNumeric;

    private:
        /// @brief Invalidated copy constructor.
        ToRetrieveDefinition(const ToRetrieveDefinition&) = delete;

        /// @brief Invalidated assignment operator.
        ToRetrieveDefinition& operator=(const ToRetrieveDefinition&) = delete;
    };

    /**
     * @brief Constructor
     *
     * Gets a list of retriever definitions. Please note that the retrievers are
     *  not deleted!
     */
    SAXWeightsHandler(const std::vector<ToRetrieveDefinition*>& defs, const std::string& file);

    /**
     * @brief Constructor
     *
     * Gets a single definition. Please note that the retrievers are not deleted!
     */
    SAXWeightsHandler(ToRetrieveDefinition* def, const std::string& file);

    /// @brief Destructor
    ~SAXWeightsHandler();

protected:
    /// @name inherited from GenericSAXHandler
    //@{

    /** @brief Called on the opening of a tag;
     *
     * @param[in] element ID of the currently opened element
     * @param[in] attrs Attributes within the currently opened element
     * @exception ProcessError If something fails
     * @see GenericSAXHandler::myStartElement
     */
    void myStartElement(int element, const SUMOSAXAttributes& attrs);

    /** @brief Called when a closing tag occurs
     *
     * @param[in] element ID of the currently opened element
     * @exception ProcessError If something fails
     * @see GenericSAXHandler::myEndElement
     */
    void myEndElement(int elemente);

    //@}

private:
    /// @brief Parses the data of an edge or lane for the previously read times
    void tryParse(const SUMOSAXAttributes& attrs, bool isEdge);

    /// @brief Parses the data of an edgeRelation for the previously read times
    void tryParseEdgeRel(const SUMOSAXAttributes& attrs);

    /// @brief Parses the data of an tazRelation for the previously read times
    void tryParseTazRel(const SUMOSAXAttributes& attrs);

    /// @brief List of definitions what shall be read and whereto stored while parsing the file
    std::vector<ToRetrieveDefinition*> myDefinitions;

    /// @brief the id of the interval being parsed
    std::string myCurrentID;

    /// @brief the begin of the time period that is currently processed
    double myCurrentTimeBeg;

    /// @brief the end of the time period that is currently processed
    double myCurrentTimeEnd;

    /// @brief the edge which is currently being processed
    std::string myCurrentEdgeID;

    /// @brief we made the copy constructor invalid
    SAXWeightsHandler(const SAXWeightsHandler& src) = delete;

    /// @brief we made the assignment operator invalid
    SAXWeightsHandler& operator=(const SAXWeightsHandler& src) = delete;
};
